﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using System.Runtime.Serialization;
using Xww.IO.Serialize;
using System.Text.RegularExpressions;

/*
namespace Xww.LCV2 {
    [Serializable]
    public class LCS : IEquatable<LCS>, IEqualityComparer<LCS>, IComparable<LCS>, IComparer<LCS>, IFormattable, System.Runtime.Serialization.ISerializable {

        private List<LCSUnit> units;
        public List<LCSUnit> Units {
            get { return units; }
        }

        private int support;
        public int Support {
            get { return support; }
            set { support = value; }
        }
        public int Length {
            get { return units.Count; }
        }
        public int? Support2 { get; set; }
        public double? SupportDifference { get; set; }
        public double? SupportQuotient { get; set; }
        public double? PValue { get; set; }
        public LCS LCVString { get { return this; } }
        public override string ToString() {
            StringBuilder rst = new StringBuilder();
            string format = "{0} ";
            for (int i = 0; i < Length; i++) {
                if (i == Length - 1) { format = "{0}"; }
                rst.AppendFormat(format, Units[i]);
            }
            if (Support > 0) { rst.AppendFormat(" {0}", Support); }
            return rst.ToString();
        }

        public string ToPureStringWithoutSupport() {
            StringBuilder rst = new StringBuilder();
            string format = "{0} ";
            for (int i = 0; i < Length; i++) {
                if (i == Length - 1) { format = "{0}"; }
                rst.AppendFormat(format, Units[i]);
            }
            return rst.ToString();
        }

        public LCS(int support, params LCSUnit[] units ){
            this.support = support;
            this.units = new List<LCSUnit>(units.Length);
            Array.Sort<LCSUnit>(units);
            this.units.AddRange(units);
        }


        public LCSUnit this[int index] {
            get {
                if (index < 0 || index >= units.Count) {
                    throw new ArgumentException("Index error when getting LCSUnit", "Index");
                }
                return units[index];
            }
        }
        #region 重载字符串到 LCS 的强制转换操作

        public static explicit operator LCS(string str) {
            string[] strArray = str.Split(default(char[]), StringSplitOptions.RemoveEmptyEntries);
            int support = 0;
            if (strArray.Length < 1) {
                throw new InvalidCastException(string.Format("构建 LCS 的字符串[{0}]不符合规范！\n合法的 LCS 字符串应包括若干个 LCSUnit 和结尾的一个支持数(可选)，例：A1 B2 C3 5", str));
            }
            List<LCSUnit> list = new List<LCSUnit>();
            int index = 0;     // 指示最后一位是否包含支持数信息
            try {
                if (int.TryParse(strArray[strArray.Length - 1], out support)) {
                    index = 1;
                }
                for (int i = 0; i < strArray.Length - index; i++) {
                    list.Add((LCSUnit)strArray[i]);
                }
            }
            catch {
                throw new InvalidCastException(string.Format("构建LCS的字符串[{0}]不符合规范！\n合法的LCS字符串应包括若干个LCSUnit和结尾的一个支持数(可选)，例：A1 B2 C3 5", str));
            }
            LCS LCS = new LCS(support, list.ToArray());
            return LCS;
        }
        #endregion

        public bool IsFitForQSet(IEnumerable<string> Qset, int threshold) {
            this.Support = 0;
            foreach (string sequence in Qset) {
                this.Support += CountInSequnece(sequence, true);
            }
            return this.Support >= threshold;
        }

        public int CountInSequnece(string sequence, bool locationAbsolute) {
            if (locationAbsolute) {
                foreach (LCSUnit item in this.Units) {
                    if (item.Location > sequence.Length || sequence[item.Location - 1] != item.AA) {
                        return 0;
                    }
                }
                return 1;
            }

            int rst = 0;
            for (int i = 0, j = 0; i < sequence.Length; i++) {
                int offset = this[0].Location - i;
                for (j = 0; j < this.Length; j++) {
                    if (this[j].Location - offset >= sequence.Length || this[j].AA != sequence[this[j].Location - offset]) { break; }
                }
                if (j == this.Length) { rst++; }
            }
            return rst;
        }
        /// <summary>Determine if a LCV is contained in a protein sequence. (Relative position)</summary>
        public bool IfContainedInSequence(string sequence) {
            for (int i = 0, j = 0; i < sequence.Length; i++) {
                int offset = this[0].Location - i;
                for (j = 0; j < this.Length; j++) {
                    if (this[j].Location - offset >= sequence.Length || this[j].AA != sequence[this[j].Location - offset]) { break; }
                }
                if (j == this.Length) { return true; }
            }
            return false;
        }
        /// <summary>Determine if a LCV is contained in a protein sequence. (Relative position)</summary>
        public bool IfContainedInSequence(string sequence, bool isAbsolutePosition) {
            if (!isAbsolutePosition)
                return IfContainedInSequence(sequence);
            foreach (LCSUnit item in this.Units) {
                if (item.Location > sequence.Length || sequence[item.Location - 1] != item.AA) {
                    return false;
                }
            }
            return true;
        }

        public void RefineToRelative() {
            int offset = this[0].Location - 1;
            for (int i = 0; i < this.Length; i++) {
                LCSUnit item = this[i];
                item.Offset(offset);
                this.units[i] = item;
            }
        }
        public void ResetSupportNumber() {
            this.support = 0;
        }
        public void ResetSuppor2tNumber() {
            this.Support2 = 0;
        }

        #region IEquatable<LCS> members

        public bool Equals(LCS other) {
            if (this.Length != other.Length) { return false; }
            for (int i = 0; i < this.Length; i++) {
                if (!this[i].Equals(other[i])) {
                    return false;
                }
            }
            return true;
        }

        #endregion

        #region IEqualityComparer<LCS> 成员

        public bool Equals(LCS x, LCS y) {
            return x.Equals(y);
        }

        public int GetHashCode(LCS obj) {
            return obj.ToPureStringWithoutSupport().GetHashCode();
        }

        static LCS instance = new LCS(0);
        public static LCS InstanceForHash {
            get { return instance; }
        }

        #endregion

        public bool IsParentOf(LCS sub) {
            return sub.Units.All(o => this.Units.Contains(o));
        }

        //todo 需要进一步修正
        public static bool CanImerge(LCS one, LCS other) {
            if (one == null || other == null || one.Length != other.Length) { return false; }
            if (one.Length == 1) { return ! one[0].Equals(other[0]); }
            for (int i = 0; i < one.Length - 1; i++) {
                if (!one[i].Equals(other[i])) { return false; }
            }
            return (one[one.Length - 1].Location < other[other.Length - 1].Location);
                //return true;
        }
        public static LCS Imerge(LCS one, LCS other) {
            int length = one.Length + 1;
            LCSUnit[] array = new LCSUnit[length];
            one.Units.CopyTo(array);
            array[length - 1] = other.Units[other.Length - 1];
            return new LCS(0, array);
        }
        public static LCS ImergeFirstLast(LCS first, LCS last) {
            int length = first.Length + 1;
            LCSUnit[] array = new LCSUnit[length];
            first.Units.CopyTo(array);
            LCSUnit lastUnit=  last[last.Length-1];
            array[length - 1] = new LCSUnit(lastUnit.AA, lastUnit.Location + first[1].Location - first[0].Location);
            return new LCS(0, array);
        }


        #region IComparable<LCS> 成员

        public int CompareTo(LCS other) {
            int rst = 0;
            for (int i = 0; i < this.Length; i++) {
                if (i > other.Length - 1)
                    return this[i].Location;
                rst = this[i].CompareTo(other[i]);
                if (rst != 0)
                    return rst;
            }
            if (this.Length > other.Length)
                return this[other.Length].Location;
            else return 0;
        }

        #endregion

        #region IFormattable 成员

        public string ToString(string format, IFormatProvider formatProvider) {
            if (string.IsNullOrEmpty(format))
                return ToString();
            else
                return ToString(format);
        }
        public string ToString(string separator) {
            StringBuilder rst = new StringBuilder();
            rst.Append(this[0].AA);
            for (int i = 1; i < Length ; i++) {
                int span = this[i].Location - this[i - 1].Location - 1;
                for (int j = 0; j < span; j++)
                    rst.Append(separator);
                rst.Append(this[i].AA);
            }
            //if (this.Length > 1) rst.Append(this[this.Length - 1].AA);
            return rst.ToString();
        }

        #endregion

        const char SEPARTOR = '.';

        public LCS SubFirstLCS {
            get {
                if (subFirstLCS == null) {
                    LCSUnit[] subArray = new LCSUnit[this.Length - 1];
                    this.Units.CopyTo(0, subArray, 0, subArray.Length);
                    subFirstLCS = new LCS(this.Support, subArray);
                }
                return subFirstLCS;
            }
        }
        LCS subFirstLCS;
        public LCS SubLastLCS {
            get {
                if (subLastLCS == null) {
                    LCSUnit[] subArray = new LCSUnit[this.Length - 1];
                    int offset = this[1].Location - this[0].Location;
                    for (int i = 0; i < subArray.Length; i++) {
                        subArray[i] = this[i + 1];
                        subArray[i].Location -= offset;
                    }
                    subLastLCS = new LCS(this.Support, subArray);
                }
                return subLastLCS;
            }
        }
        LCS subLastLCS;
        public string SubFirstString {
            get {
                if (subFirstString == null) {
                    StringBuilder sb = new StringBuilder();
                    int lastLocation = this[1].Location;
                    sb.Append(this[1].AA);
                    for (int i = 2; i < this.Length; i++) {
                        int interval = this[i].Location - lastLocation - 1;
                        if (interval > 0)
                            sb.Append(new string(SEPARTOR, interval));
                        sb.Append(this[i].AA);
                        lastLocation = this[i].Location;
                    }
                    subFirstString = sb.ToString();
                }
                return subFirstString;
            }
        }
        string subFirstString;
        public string SubLastString {
            get {
                if (subLastString == null) {
                    StringBuilder sb = new StringBuilder();
                    int lastLocation = this[0].Location;
                    sb.Append(this[0].AA);
                    for (int i = 1; i < this.Length-1; i++) {
                        int interval = this[i].Location - lastLocation - 1;
                        if (interval > 0)
                            sb.Append(new string(SEPARTOR, interval));
                        sb.Append(this[i].AA);
                        lastLocation = this[i].Location;
                    }
                    subLastString = sb.ToString();
                }
                return subLastString;
            }
        }
        string subLastString;
        internal int LastLocation{
            get { return this[Length - 1].Location; }
        }

        Regex regex;
        public Regex REGEX {
            get {
                if (regex == null)
                    regex = this.GetRegex();
                return regex;
            }
        }

        string pureString=null;
        public string PureString {
            get {
                if (pureString == null) {
                    StringBuilder sb = new StringBuilder();
                    int offset = this[0].Location;
                    int lastLocation = this[0].Location;
                    sb.Append(this[0].AA);
                    for (int i = 1; i < this.Length; i++) {
                        int interval = this[i].Location - lastLocation - 1;
                        if (interval > 0)
                            //sb.AppendFormat("\\w{{{0}}}", interval);
                            sb.Append(new string(SEPARTOR, interval));
                        sb.Append(this[i].AA);
                        lastLocation = this[i].Location;
                    }
                    pureString = sb.ToString();
                }
                return pureString;
            }
        }


        #region IComparer<LCS> 成员

        public int Compare(LCS x, LCS y) {
            return x.CompareTo(y);
        }

        #endregion

        #region ISerializable 成员

        public void GetObjectData(SerializationInfo info, StreamingContext context) {
            SerializationWriter writer = new Xww.IO.Serialize.SerializationWriter();
            writer.Write(Support);
            writer.WriteNullable(Support2);
            writer.WriteNullable(SupportDifference);
            writer.WriteNullable(SupportQuotient);
            writer.WriteNullable(PValue);
            writer.Write(Length);
            writer.Write(units);
            info.AddValue("data", writer.ToArray());
        }
        private LCS(SerializationInfo info, StreamingContext context) {
            Xww.IO.Serialize.SerializationReader reader = new Xww.IO.Serialize.SerializationReader(
                (byte[])info.GetValue("data", typeof(byte[])));
            Support = reader.ReadInt32();
            Support2 = reader.ReadNullableInt32();
            SupportDifference = reader.ReadNullableDouble();
            SupportQuotient = reader.ReadNullableDouble();
            PValue = reader.ReadNullableDouble();
            int length = reader.ReadInt32();
            units = reader.ReadList<LCSUnit>();
        }

        #endregion
    }
}
*/